package managedbean;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.imageio.ImageIO;
import javax.persistence.PersistenceException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.Client;

import org.apache.log4j.Logger;
import org.primefaces.event.FileUploadEvent;

import sun.misc.BASE64Encoder;
import dao.ClientDao;

@ManagedBean(name = "connexionManagedBean")
@SessionScoped
public class ConnexionManagedBean {

	private Client user;
	private String password;
	private String confirmation;
	private String identifiant;
	private boolean connected;
	private boolean rememberMe;
	private boolean admin;
	private String savedView;
	
	private MessageDigest shaEncoder;

	public static Logger log = Logger.getLogger(ConnexionManagedBean.class);
	@ManagedProperty(value = "#{clientDao}")
	private ClientDao clientDao;


	public String getAvatar() {
		if (user.getAvatar() != null && user.getAvatar() == true) {
			ExternalContext extContext = (ExternalContext) FacesContext.getCurrentInstance().getExternalContext();
			return "/resources/img/avatar" + getUser().getId();
		} else
			return "";
	}

	public Client getUser() {
		return user;
	}

	public void setUser(Client user) {
		this.user = user;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getIdentifiant() {
		return identifiant;
	}

	public void setIdentifiant(String identifiant) {
		this.identifiant = identifiant;
	}

	public boolean isConnected() {
		return connected;
	}

	public void setConnected(boolean connected) {
		this.connected = connected;
	}

	public boolean isRememberMe() {
		return rememberMe;
	}

	public void setRememberMe(boolean rememberMe) {
		this.rememberMe = rememberMe;
	}

	public ClientDao getClientDao() {
		return clientDao;
	}

	public void setClientDao(ClientDao clientDao) {
		this.clientDao = clientDao;
	}

	public String getConfirmation() {
		return confirmation;
	}

	public void setConfirmation(String confirmation) {
		this.confirmation = confirmation;
	}

	public String getSavedView() {
		return savedView;
	}

	public void setSavedView(String savedView) {
		this.savedView = savedView;
	}
	
	public void setAdmin(boolean isAdmin) {
		this.admin = isAdmin;
	}

	public boolean getAdmin() {
		return admin;
	}

	public ConnexionManagedBean() {

	}
	
	private String encodeKeyForUser(Client user) {
		try {
			String key = user.getLogin()+user.getPassword();
			shaEncoder.update(key.getBytes("UTF-8"));
			byte raw[] = shaEncoder.digest();
			String hash = (new BASE64Encoder()).encode(raw);
			return hash;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			throw new Error(e);
		}
	}
	
	private void addCookies() {
		HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
		Cookie userCookie = new Cookie("user", getUser().getLogin());
		userCookie.setMaxAge(Integer.MAX_VALUE);
		Cookie keyCookie = new Cookie("connection", encodeKeyForUser(getUser()));
		keyCookie.setMaxAge(Integer.MAX_VALUE);
		response.addCookie(userCookie);
		response.addCookie(keyCookie);
	}
	
	private void removeCookies() {
		HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
		Cookie userCookie = new Cookie("user", "");
		userCookie.setMaxAge(0);
		Cookie passwordCookie = new Cookie("connection","");
		passwordCookie.setMaxAge(0);
		response.addCookie(userCookie);
		response.addCookie(passwordCookie);
	}
	
	@PostConstruct
	public void loadCookies() {
		try {
			shaEncoder = MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException e) {
			log.error("Pas d'encodage disponible");
			throw new Error("Pas d'encodage disponible", e);
		}
		
		HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
		Cookie serverCookies[] = request.getCookies();
		if (serverCookies != null) {
			String connection = null;
	        for (Cookie cookie : serverCookies) {
	            if(cookie.getName().equals("user")) {
	                setIdentifiant(cookie.getValue());
	            } else if (cookie.getName().equals("connection")) {
	            	connection = cookie.getValue();
	            }
			}
	        if (getIdentifiant() != null) {
	        	Client user = getClientDao().searchClientByLogin(getIdentifiant());
	        	if (user != null && connection.equals(encodeKeyForUser(user))) {
	        		setConnected(true);
	        		setUser(user);
	        		setIdentifiant(user.getLogin());
	        		setPassword(user.getPassword());
	        		if(user.getLogin().equals("admin")){
	    				setAdmin(true);
	    			}
	        		setRememberMe(true);
	        	}
	        }
		}
	}

	public String connect() {
		String result = null;
		Client client;
		try {
			client = getClientDao().connect(getIdentifiant(), getPassword());
		} catch (PersistenceException e) {
			client = null;
			log.warn("User not found");
			log.warn(e.getMessage());
		}
		if (client != null && client.getPassword().equals(getPassword())) {
			setConnected(Boolean.TRUE);
			if(client.getLogin().equals("admin")){
				setAdmin(true);
			}
			this.setUser(client);
			if (isRememberMe()) {
				addCookies();
			} else {
				removeCookies();
			}
			result = "Success";
		} else {
			if (client == null) {
				FacesMessage mess = new FacesMessage(
						FacesMessage.SEVERITY_ERROR, "login inconnu",
						"L'utilisateur n'est pas enregistré");
				FacesContext.getCurrentInstance().addMessage("connexionForm", mess);
			} else {
				FacesMessage mess2 = new FacesMessage(
						FacesMessage.SEVERITY_ERROR, "Bad password",
						"Erreur dans le mot de passe, veuillez recommencer.");
				FacesContext.getCurrentInstance().addMessage("connexionForm", mess2);
			}
			if (getPassword() == null || getPassword().equals("") ) {
				FacesMessage mess3 = new FacesMessage(
						FacesMessage.SEVERITY_ERROR, "Void Password",
						"Veuillez saisir un mot de passe.");
				FacesContext.getCurrentInstance().addMessage("connexionForm", mess3);
			}
			result = "Rejected";
		}
		return result;
	}

	public boolean hasAvatar() {
		return !getAvatar().equals("");
	}

	public String modify() {
		String result = null;
		boolean valid = true;
		log.info("Modification de l'utilisateur");
		if (!getIdentifiant().equals(getUser().getLogin())) {
			if (getClientDao().exists(getIdentifiant())) {
				valid = false;
				FacesMessage mess = new FacesMessage(
						FacesMessage.SEVERITY_ERROR, "Login existant",
						"L'utilisateur existe déjà");
				FacesContext.getCurrentInstance().addMessage("modif", mess);
			}
		}
		if (!getPassword().equals(getUser().getPassword())
				&& !getPassword().equals(getConfirmation())) {
			valid = false;
			FacesMessage mess = new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"Echec confirm", "Vous devez rentrer le même mot de passe");
			FacesContext.getCurrentInstance().addMessage("modif", mess);
		}
		if (valid == true) {
			if (!getIdentifiant().equals(getUser().getLogin())) {
				getUser().setLogin(getIdentifiant());
			}
			if (!getPassword().equals(getUser().getPassword())) {
				getUser().setPassword(getPassword());
			}
			if (getClientDao().update(getUser())) {
				result = "modified";
				log.info("réussi");
			} else {
				log.error("error");
				result = "error";
			}
		} else {
			log.warn("fail");
			result = "rejected";
		}
		return result;
	}

	public void upload(FileUploadEvent event) {
		log.info("entrée dans upload");
		ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
		File result = new File(extContext.getRealPath("/resources/img") + "/avatar" + getUser().getId());

		try {

			BufferedImage originalImage = ImageIO.read(event.getFile().getInputstream());
			int thumb_width = 100;
			int thumb_height = 100;
			BufferedImage resizedImage = new BufferedImage(thumb_width, thumb_height, originalImage.getType());
			Graphics2D g = resizedImage.createGraphics();
			g.drawImage(originalImage, 0, 0, thumb_width, thumb_height, null);
			g.dispose();

			ImageIO.write(resizedImage, "png", result);

			FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
			FacesContext.getCurrentInstance().addMessage("Download", msg);

			user.setAvatar(true);
			if (getClientDao().update(getUser())) {
				log.info("enregistrement avatar réussi");
			} else {
				log.error("enregistrement avatar echoué");

			}

		} catch (IOException e) {
			e.printStackTrace();
			FacesMessage error = new FacesMessage("The files were not uploaded!");
			FacesContext.getCurrentInstance().addMessage("Download", error);
		}
	}

	public String disconnect() {
		setConnected(Boolean.FALSE);
		this.setUser(null);
		this.setAdmin(false);
		return "Disconnected";
	}
	
	public void checkConnected() {
		if (getUser() == null || isConnected() == false) {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			setSavedView(facesContext.getViewRoot().getViewId());
		    String outcome = "need_connection"; 
		    FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Vous devez être connecté", "Vous devez être connecté");
		    facesContext.addMessage(null, message);
		    facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, outcome);
		}
	}
	
	public void connectToOldView() {
		String result = connect();
		if (result.equals("Success")) {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, getSavedView());
			setSavedView(null);
		}
	}
	
	public String rejectRestrictedAccess() {
		setSavedView(null);
		return "index";
	}

}
